package advanced.java.ch01.p1;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.UnknownHostException;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 客户端stub的工厂类
 * 
 * @author shuangzh
 *
 */
public class ClientStubFactory {

	private Linker linker; // 链接器
	private Class clazz; // 接口类
	private String interfaceName; // 接口类名

	public ClientStubFactory(String interfaceName, String address, int port)
			throws ClassNotFoundException, UnknownHostException, IOException {
		this.setInterfaceName(interfaceName);
		linker = SocketLinker.newClientSocketLinker(address, port);
	}

	private AtomicLong id = new AtomicLong();

	class ProxyHandler implements InvocationHandler {

		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {

			RpcRequest req = new RpcRequest();

			req.setId(id.getAndIncrement());
			req.setMethodName(method.getName());
			req.setParameterTypes(method.getParameterTypes());
			req.setArgs(args);

			linker.sendObject(req);
			RpcResponse rsp = (RpcResponse) linker.receiveObject();

			return rsp.getResult();
		}
	}

	public Object getStub() throws Exception {
		return Proxy.newProxyInstance(this.getClass().getClassLoader(),
				new Class[] { clazz }, new ProxyHandler());
	}

	public Linker getLinker() {
		return linker;
	}

	public void setLinker(Linker linker) {
		this.linker = linker;
	}

	public Class getClazz() {
		return clazz;
	}

	public void setClazz(Class clazz) {
		this.clazz = clazz;
	}

	public String getInterfaceName() {
		return interfaceName;
	}

	public void setInterfaceName(String interfaceName)
			throws ClassNotFoundException {
		this.interfaceName = interfaceName;
		this.clazz = Class.forName(interfaceName);
	}

}
